package com.zzm.validate.web;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.commons.validator.Arg;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.Form;
import org.apache.commons.validator.Msg;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorException;
import org.apache.commons.validator.ValidatorResult;
import org.apache.commons.validator.ValidatorResults;

import com.zzm.validate.ValidateException;
import com.zzm.validate.web.injector.ArgInjector;
import com.zzm.validate.web.injector.ArgInjectorFactory;

/**
 * 验证单个bean 或form的功能类
 *
 */
public class SimpleFormValidator extends AbstractFormValidator {

	public SimpleFormValidator(WebValidateResources validatorResources,
			ResourceBundle defaultBundle,
			ArgInjectorFactory argInjectorFactory, ArgPattern argPattern) {
		super(validatorResources, defaultBundle, argInjectorFactory, argPattern);
	}

	/**
	 * @return 返回一个错误信息Map
	 */
	public Object validate(String formName, Object bean, Object[] params)
			throws ValidateException {
		Validator validator = new Validator(validatorResources, formName);
		this.setParameters(validator, bean, params);
		ValidatorResults results;
		try {
			results = validator.validate();
		} catch (ValidatorException e) {
			throw new ValidateException(e);
		}
		Object messages = this.createMessages(bean, formName, results);
		return messages;
	}
	
	/**
	 * 设置验证时所要传给验证方法的参数
	 */
	protected void setParameters(Validator validator, Object bean, Object[] params) {
		validator.setParameter(Validator.BEAN_PARAM, bean);
		if (null != params) {
			for (Object param : params) {
				validator.setParameter(param.getClass().getName(), param);
			}
		}
	}

	/**
	 * 创建bean验证后的错误信息
	 */
	@SuppressWarnings("rawtypes")
	protected Object createMessages(Object bean, String formName, ValidatorResults results) {
		Form form = validatorResources.getForm(Locale.getDefault(), formName);
		Set propertyNameSet = results.getPropertyNames();
		Map<String, String> messageMap = new HashMap<String, String>();
		for (Object propertyName : propertyNameSet) {
			Field field = (Field) form.getField(propertyName.toString());
			ValidatorResult result = results.getValidatorResult(propertyName.toString());
			Iterator actionIter = result.getActions();
			while (actionIter.hasNext()) {
				String actName = (String) actionIter.next();
				if(result.isValid(actName)) {
					continue;
				}
				ValidatorAction action = validatorResources.getValidatorAction(actName);
				String message = this.getFieldMessage(bean, form, field, action);
				if (null != message) {
					messageMap.put(field.getProperty(), message);
				}
			}
		}
		return messageMap.size() > 0 ? messageMap : null;
	}

	/**
	 * 获取单个字段的错误资源信息, 并注入参数
	 */
	protected String getFieldMessage( Object bean, Form form, 
									  Field field, ValidatorAction action ) {
		
		String resource = this.getResource(field, action);
		String message = this.injectArgs(resource, bean, field, form);
		return message;
	}
	
	/**
	 * 获取未注入参数的资源错误信息
	 */
	protected String getResource(Field field, ValidatorAction action) {
		String resource = null;
		Msg msg = field.getMessage(action.getName());
		if(msg == null) {
			resource = (String) validatorResources.getConstants().get(action.getMsg());
			if(resource == null) {
				resource = this.getResourceFromBundle(action.getMsg());
			}
		} else {
			if(msg.isResource()) {
				resource = this.getResourceFromBundle(msg.getBundle());
			} else {
				resource = msg.getBundle();
			}
		}
		return resource;
	}
	
	/**
	 * 从外部文件获取资源信息
	 */
	protected String getResourceFromBundle(String key) {
		try {
			return defaultBundle.getString(key);
		} catch(NullPointerException e) {
			throw new RuntimeException("Can't found resource [key=" + key + "] anywhere");
		}
	}
	
	/**
	 * 对资源错误信息注入参数
	 */
	protected String injectArgs(String resource, Object bean, Field field, Form form) {
		String message = resource;
		int index = 0;
		while (true) {
			String argIndex = this.argPattern.indexOf(index);
			if (resource.contains(argIndex)) {
				Arg arg = field.getArg(index);
				if(arg == null) {
					throw new RuntimeException("Field:" + field.getProperty() + " hasn't element arg which it's potision is " + index);
				}
				ArgInjector injector = argInjectorFactory.getArgInjector(arg.getKey());
				message = injector.inject(bean, form, field, arg, message);
				index++;
			} else {
				break;
			}
		}
		return message;
	}
	
	public WebValidateResources getValidatorResources() {
		return validatorResources;
	}

	public ResourceBundle getDefaultBundle() {
		return defaultBundle;
	}

	public ArgInjectorFactory getArgInjectorFactory() {
		return argInjectorFactory;
	}

	public ArgPattern getArgPattern() {
		return argPattern;
	}
}
